package com.me.myFramework.myDI.util;

import com.me.myFramework.myDI.annotation.MyComponent;

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 手写 Spring: 模拟注解配置
 *
 * @author ME
 * @date   2019/12/12
 */
public class AnnotationConfigApplicationContext {

    private Map<String, MyBeanDefinition> beanDefinitions = new HashMap<>();
    private Map<String, Object> beans = new HashMap<>();

    public AnnotationConfigApplicationContext() {
        super();
    }

    public void scan(String basePackage) {
        String path = this.getClass().getResource("/").getPath();
        String packageSearchPath = path + basePackage.replaceAll("\\.", "/");

        Set<String> allPath = findAllClassFile(new File(packageSearchPath), basePackage);

        // allPath.stream().forEach(System.out::println);
        allPath.stream().forEach(className -> {
            try {
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(MyComponent.class)) {
                    String beanName = clazz.getAnnotation(MyComponent.class).value();
                    Constructor<?>[] constructors = clazz.getDeclaredConstructors();
                    // TODO 不能直接 new, 可能没有空参构造
                    for (Constructor<?> constructor : constructors) {
                        constructor.getGenericParameterTypes();
                    }
                    this.beans.put(beanName, clazz.newInstance());
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                throw new RuntimeException("对象 [" + className + "] 的构造方法调用失败: ", e);
            }
        });
        System.out.println();
    }

    private Set<String> findAllClassFile(File basePackageFile, String basePackage) {
        Set<String> allDirectory = new HashSet<>();

        File[] list = basePackageFile.listFiles();
        for (File f : list) {
            if (f.isDirectory()) {
                allDirectory.addAll(findAllClassFile(f, basePackage + "." + f.getName()));
            } else if (f.isFile() && f.getName().endsWith(".class")) {
                String className = basePackage + "." + f.getName().replace(".class", "");
                allDirectory.add(className);
            }
        }
        // Arrays.stream(list).filter(file -> file.isFile());

        return allDirectory;
    }

}
